STM Board Dev Setup on NixOS
Written: | 2025-08-11 |
Tags: | #arm #nixos |
After trying to get stm32CubeIDE working on NixOS and failing at every possible step, I decided to instead use VSCode+Plugins to work. This may or may not be a good idea.
- Step 1: Install VSCode and the "STM32Cube for Visual Studio Code" extension
- Step 2: Install STM32CubeCLT
- Step 3: Install STM32CubeMX
Installing STM32CubeCLT
Attempt 1:
- Download it from their website
- Extract the zip
unzip <name>.zip
- Run the installer
steam-run <name>
- It fails when it tries to install something into
/etc/...
Attempt 2:
With the help of this little script, we can extract these self-extracting-scripts made with Makeself (requires fish and ripgrep):
function mkself-extract
if test (count $argv) -ne 2
echo "Usage: mkself-extract <file> <dest>" >&2
return 1
end
set -l file $argv[1]
set -l dest $argv[2]
# Get byte offset where the string starts (first match)
set -l offset (LC_ALL=C rg --byte-offset --text '\./(?-u:\x00)' $file | head -n1 | cut -d: -f1)
if test -z "$offset"
echo "String not found in file" >&2
return 2
end
# create dest folder
if ! mkdir $dest
echo "$dest already exists!" >&2
return 3
end
# Print everything after the string
tail -c +(math 1 + $offset) "$file" | tar -xf - -C $dest
end
We can use this by running mkself-extract st-stm32cubeclt_1.19.0_25876_20250729_1159_amd64.sh stm32cubectl-install
. This will create and populate the stm32cubectl-install
folder. This will contain the stm32cubectl
installer data. All we need from there is the tar.gz
archive, which we can extract like this: tar -xcf stm32cubectl-install/st-stm32cubeclt_1.19.0_25876_20250729_1159_amd64.tar.gz -C st-stm32cubeclt_1.19.0
.
We now have a functional folder with binaries that work out-of-the-box on NixOS!
Installing CubeMX:
Installing CubeMX on NixOS is a lost cause as it includes too much garbage like bundled browsers that are not in binaries that can be patched for some reason. It's super flakey, and doesn't even work properly through steam-run
.
Instead, I recommend running it in podman with X passthrough: (assuming that your st-related stuff including CubeMX is located in ~/st
)
$ podman run -it --rm -e DISPLAY -v ~/.Xauthority:/root/.Xauthority:Z -v ~/st:/st:Z -v ~/.stm32cubemx/:/root/.stm32cubemx:Z -v ~/STM32Cube/:/root/STM32Cube/ --net=host ubuntu
$ apt update && apt install -y xorg && ~/st/STM32CubeMX/STM32CubeMX
Installing the UDEV rules and ST-LINK-SERVER
The udev rules are included alongside the CubeCTL installer and can be extracted by running mkself-extract stm32cubectl-installer/st-stlink-udev-rules-1.0.3-2-linux-noarch.sh udevrules
, which will then contain a few udev rules. Installing these works through supplying a special package to services.udev.packages
. We'll get to this later, because:
stlink-server
is a special binary that needs to be root owned. I will prepare a small nix package that contains these1:
{ pkgs ? import <nixpkgs> { system = builtins.currentSystem; }
, stdenv ? pkgs.stdenv
, lib ? pkgs.lib
}:
stdenv.mkDerivation rec {
pname = "stm32dev";
version = "1.18.0";
doNotUnpack = true;
src = ./.;
nativeBuildInputs = [
pkgs.autoPatchelfHook
];
buildInputs = with pkgs; [
libusb1
];
installPhase = ''
runHook preInstall
# install the stlink-server binary as root
patchelf bin/stlink-server
install -D -t $out/bin/ bin/stlink-server
# install udev rules
install -D -t $out/etc/udev/rules.d/ udev/*.rules
runHook postInstall
'';
meta = with lib; {
homepage = "https://www.st.com/en/development-tools/stm32cubeide.html";
description = "STM32 Misc Dependencies (udev rules and stlink-server)";
platforms = platforms.linux;
};
# include using (callPackage /home/<user>/path/to/this/file.nix {})
}
This file should be located in a folder that also contains the extracted udev rules in a subfolder udev
and an unmodified stlink-server
binary. Here is my folder layout:
nix-pkg
├── bin
│ └── stlink-server
├── st-dev.nix
└── udev
├── 49-stlinkv1.rules
├── 49-stlinkv2-1.rules
├── 49-stlinkv2.rules
└── 49-stlinkv3.rules
This then needs to be installed as a package, as well as added to the udev rules:
# ...
# List packages installed in system profile.
environment.systemPackages = with pkgs; [
# ...
# my stm32cube stuff:
(pkgs.callPackage /home/anton/st/nix-pkg/st-dev.nix {})
];
# also install the udev rules
services.udev.packages = [
(pkgs.callPackage /home/anton/st/nix-pkg/st-dev.nix {})
];
# ...
-
I am actually not sure if this needs to be globally installed anymore, but it doesn't hurt to try? Anyway... ↩